﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web.Mvc;
using Citi.Helpers;
using Citi.Scheduler.Domain;
using Citi.Scheduler.WebUi.Helpers;
using Citi.Scheduler.WebUi.Models;
using Citi.SecurityHelper;

namespace Citi.Scheduler.WebUi.Controllers
{
    public class MachineController : ControllerBase<MachineModel, Machine>
    {
        private const string ServiceExecutionName = "Citi Scheduler Execution Service";
        private const string ServiceMonitorName = "Citi Scheduler Monitor Service";
        private const string ServiceSchedulerName = "Citi Scheduler Service";

        public ActionResult Index()
        {
            return IndexBase(true);
        }

        public ActionResult Form()
        {
            return View();
        }

        [OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
        public ActionResult ActionForm(int? id)
        {
            return ActionBase(id, true);
        }

        [HttpPost]
        public ActionResult ActionForm(MachineModel model)
        {
            return ActionBase(model, true);
        }

        public ActionResult Delete(int id)
        {
            return DeleteBase(id, true);
        }

        public ActionResult Details(int id)
        {
            return ActionBase(id, true);
        }

        public ActionResult PerformanceReport()
        {
            FillViewBagReport();
            return View();
        }

        [ValidateInput(false)]
        [OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
        public JsonResult GeneratePerformanceReport(DateTime startDate, DateTime endDate, int machineId = 0)
        {
            var executions = new RoutineExecution().GetByMachineIdAndDate(startDate, endDate, machineId);
            //var executed = executions.Where(x => x.EndsOn.HasValue && x.StartsOn.HasValue);

            //var machines = executed.Select(x => x.Machine).Distinct().ToList();

            //var series = machines.Select(machine => new
            //{
            //    Name = machine.HostName,
            //    Data = executed.Where(x => x.MachineId == machine.Id).Select(x => Math.Round((x.EndsOn.Value - x.StartsOn.Value).TotalMinutes, 2)).ToArray()
            //}).ToArray();

            var errorChartInfomation = ChartsHelper.GetErrorMachineDataChart(executions);

            return Json(new
            {
                errorsSeries = errorChartInfomation.Series,
                errorsCategories = errorChartInfomation.Categories,
                noData = false
            }, JsonRequestBehavior.AllowGet);
        }

        public void FillViewBagReport(int? machineId = null)
        {
            var machines = new Machine().SelectByTypeCenter(MachineCenter.Execution).OrderBy(m => m.HostName);
            ViewBag.Machines = machines.ToSelectList(x => x.HostName, x => x.Id.ToString(), "All",
                machineId.HasValue ? machineId.Value.ToString() : string.Empty);
        }

        public ActionResult MemoryUsage()
        {
            FillViewBagReport();
            return View();
        }

        public JsonResult GenerateMemoryUsageReport(DateTime date, int machineId = 0)
        {
            var executions = new RoutineExecution().GetByMachineIdAndDate(date, machineId);
            var categories = new List<string>();
            var memories = new List<MemoryUsage>();
            var series = new List<long>();

            foreach (var execution in executions)
            {
                var path = Path.Combine(MemoryUsagePath, execution.MachineId.ToString(), string.Concat(execution.Id, ".xml"));

                if (!System.IO.File.Exists(path)) continue;

                var routineMemories = XmlHelper.DeserializeFromXml<List<MemoryUsage>>(path);
                routineMemories.ForEach(x =>
                    {
                        x.RoutineExecutionId = execution.Id;
                        x.Date = System.IO.File.GetCreationTime(path).AddSeconds(x.Seconds);
                    });

                memories.AddRange(routineMemories);
            }

            for (int i = 0; i < 24; i++)
            {
                var time = date.AddHours(i);

                if ((date == DateTime.Today && time.TimeOfDay > DateTime.Now.TimeOfDay) || date > DateTime.Today) break;

                categories.Add(time.ToString("HH:mm"));
                var timeExecution = memories.Where(x => x.Date.TimeOfDay > time.TimeOfDay && x.Date.TimeOfDay < time.AddHours(1).TimeOfDay);

                series.Add(timeExecution.Any() ? Convert.ToInt64(timeExecution.Average(x => x.Size)) : 0);
            }

            return Json(new
            {
                series = new { Data = series.ToArray(), Name = "Executions" },
                categories,
                noData = false
            }, JsonRequestBehavior.AllowGet);
        }

        public JsonResult SelectByRoutineConfigurations(int routineId)
        {
            var machines = new Machine().SelectByRoutineConfigurations(routineId).Select(x => x.HostName);

            return Json(new { machines = machines.ToArray() }, JsonRequestBehavior.AllowGet);
        }

        [OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
        public ActionResult CurrentExecution()
        {
            return PartialView(new MachineModel().CreateModel(new Machine().SelectByTypeCenter(MachineCenter.Execution)));
        }

        public ActionResult CurrentExecutionText()
        {
            var machines = new Machine().SelectByTypeCenter(MachineCenter.Execution);

            var executions = new List<MachineCurrentExecutionTextModel>();

            using (Citi.SecurityHelper.ImpersonateCitiUser.GetImpersonateUser("lac_bra_Ftools", @"lac\lac_bra_ftools", "Ferrari3k10"))
            {

                foreach (var machine in machines)
                {
                    string machineName;
                    string file;

                    if (Environment.MachineName.ToUpper() == machine.HostName.ToUpper())
                    {
                        file = @"C:\";
                        machineName = machine.HostName;
                    }
                    else
                    {
                        file = string.Format(@"\\{0}\C$\", machine.FullName);
                        machineName = machine.FullName;
                    }

                    file = Path.Combine(file, @"Temp\ExecutionLog.txt");

                    var servicesRunning = new List<string>();
                    if (machine.ExecutionCenter) servicesRunning.Add(Machine.ServiceExecutionName);
                    if (machine.MonitorCenter) servicesRunning.Add(Machine.ServiceMonitorName);
                    if (machine.SchedulerCenter) servicesRunning.Add(Machine.ServiceSchedulerName);

                    if (System.IO.File.Exists(file))
                    {
                        var execution = new MachineCurrentExecutionTextModel
                        {
                            Hostname = machine.HostName,
                            MachineFullName = machineName,
                            Date = System.IO.File.GetLastWriteTime(file),
                            Description = System.IO.File.ReadAllLines(file).LastOrDefault(),
                            Services = servicesRunning.Select(x => new ServiceStatusModel { MachineName = machineName, ServiceName = x })
                        };

                        executions.Add(execution);
                    }
                    else
                    {
                        var execution = new MachineCurrentExecutionTextModel { Date = DateTime.Now, Hostname = machine.HostName, Description = "Machine not accessible" };

                        executions.Add(execution);
                    }
                }
            }

            return View(executions);
        }

        public ActionResult StartService(string machineName, string serviceName)
        {
            using (ImpersonateCitiUser.GetImpersonateUser(NetworkUser, NetworkUser, NetworkPassword))
            {
                WindowsUtil.StartService(serviceName, machineName, 30000);

                return RedirectToAction("CurrentExecutionText");
            }
        }

        public ActionResult StopService(string machineName, string serviceName)
        {
            using (ImpersonateCitiUser.GetImpersonateUser(NetworkUser, NetworkUser, NetworkPassword))
            {
                WindowsUtil.StopService(serviceName, machineName, 30000);

                return RedirectToAction("CurrentExecutionText");
            }
        }

        public ActionResult RestartService(string machineName, string serviceName)
        {
            using (ImpersonateCitiUser.GetImpersonateUser(NetworkUser, NetworkUser, NetworkPassword))
            {
                WindowsUtil.RestartService(serviceName, machineName, 30000);

                return RedirectToAction("CurrentExecutionText");
            }
        }

        [ValidateInput(false)]
        public ActionResult FullExecutionLog(string machineName)
        {
            string file = Environment.MachineName.ToUpper() == machineName.ToUpper()
                ? @"C:\"
                : file = string.Format(@"\\{0}\C$\", machineName);

            file = Path.Combine(file, @"Temp\ExecutionLog.txt");

            using (ImpersonateCitiUser.GetImpersonateUser(NetworkUser, NetworkUser, NetworkPassword))
            {
                if (System.IO.File.Exists(file))
                    return View(System.IO.File.ReadAllLines(file));

                return View(new[] { "File not found" });
            }
        }
    }
}